<template>
   <div class="bgView">
     <div :class="['json-view', length ? 'closeable' : '']" :style="'font-size:' + fontSize+'px'">
     <span @click="toggleClose" :class="['angle', innerclosed ? 'closed' : '']" v-if="length">
     </span>
       <div class="content-wrap">
         <p class="first-line">
           <span v-if="jsonKey" class="json-key">"{{jsonKey}}": </span>
           <span v-if="length">
           {{prefix}}
           {{innerclosed ? ('...' + subfix) : ''}}
           <span class="json-note">
            {{innerclosed ? (' // count: ' + length) : ''}}
           </span>
         </span>
           <span v-if="!length">{{isArray ? '[]' : '{}'}}</span>
         </p>
         <div v-if="!innerclosed && length" class="json-body">
           <template v-for="(item, index) in items">
             <json-view :closed="closed" v-if="item.isJSON" :key="index" :json="item.value"
                        :jsonKey="item.key" :isLast="index === items.length - 1"></json-view>
             <p class="json-item" v-else :key="index">
             <span class="json-key">
                 {{(isArray ? '' : '"' + item.key + '"')}}
             </span>
               :
               <span class="json-value">
                 {{item.value + (index === items.length - 1 ? '' : ',')}}
             </span>
             </p>
           </template>
           <span v-show="!innerclosed" class="body-line"></span>
         </div>
         <p v-if="!innerclosed && length" class="last-line">
           <span>{{subfix}}</span>
         </p>
       </div>
     </div>
   </div>
 </template>
 
 <script>
   export default {
     name: 'jsonView',
     props: {
       json: [Object, Array],
       jsonKey: {
         type: String,
         default: ''
       },
       closed: {
         type: Boolean,
         default: false
       },
       isLast: {
         type: Boolean,
         default: true
       },
       fontSize: {
         type: Number,
         default: 13
       }
     },
     created() {
       this.innerclosed = this.closed
       this.$watch('closed', () => {
         this.innerclosed = this.closed
       })
     },
     data() {
       return {
         innerclosed: true
       }
     },
     methods: {
       isObjectOrArray(source) {
         const type = Object.prototype.toString.call(source)
         const res = type === '[object Array]' || type === '[object Object]'
         return res
       },
       toggleClose() {
         if (this.innerclosed) {
           this.innerclosed = false
         } else {
           this.innerclosed = true
         }
       }
     },
     computed: {
       isArray() {
         return Object.prototype.toString.call(this.json) === '[object Array]'
       },
       length() {
         return this.isArray ? this.json.length : Object.keys(this.json).length
       },
       subfix() {
         return (this.isArray ? ']' : '}') + (this.isLast ? '' : ',')
       },
       prefix() {
         return this.isArray ? '[' : '{'
       },
       items() {
         if (this.isArray) {
           return this.json.map(item => {
             const isJSON = this.isObjectOrArray(item)
             return {
               value: isJSON ? item : JSON.stringify(item),
               isJSON,
               key: ''
             }
           })
         }
         const json = this.json
         return Object.keys(json).map(key => {
           const item = json[key]
           const isJSON = this.isObjectOrArray(item)
           return {
             value: isJSON ? item : JSON.stringify(item),
             isJSON,
             key
           }
         })
       }
     }
   }
 </script>
 
 <style>
   .bgView {
     background-color: #fafafa;
   }
 
   .json-view {
     position: relative;
     display: block;
     width: 100%;
     height: 100%;
     white-space: nowrap;
     padding-left: 20px;
     box-sizing: border-box;
   }
 
   .json-note {
     color: #909399;
   }
 
   .json-key {
     color: rgb(147, 98, 15);
   }
 
   .json-value {
     color: rgb(24, 186, 24);
   }
 
   .json-item {
     margin: 0;
     padding-left: 20px;
   }
 
   .first-line {
     padding: 0;
     margin: 0;
   }
 
   .json-body {
     position: relative;
     padding: 0;
     margin: 0;
   }
 
   .json-body .body-line {
     position: absolute;
     height: 100%;
     width: 0;
     border-left: dashed 1px #bbb;
     top: 0;
     left: 2px;
   }
 
   .last-line {
     padding: 0;
     margin: 0;
   }
 
   .angle {
     position: absolute;
     display: block;
     cursor: pointer;
     float: left;
     width: 20px;
     text-align: center;
     left: 0;
   }
 
   .angle::after {
     content: "";
     display: inline-block;
     width: 0;
     height: 0;
     vertical-align: middle;
     border-top: solid 4px #333;
     border-left: solid 6px transparent;
     border-right: solid 6px transparent;
   }
 
   .angle.closed::after {
     border-left: solid 4px #333;
     border-top: solid 6px transparent;
     border-bottom: solid 6px transparent;
   }
 </style>